using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;

namespace Universe.Remoting.Extensions
{
    public static class TrafficDefaultInfo
    {
        public static readonly TrafficStatistic ServerTraffic = new TrafficStatistic();
        public static readonly TrafficStatistic ClientTraffic = new TrafficStatistic();

        static TrafficDefaultInfo()
        {
            TrafficStatisticConfiguration.Server.Update += UpdateServer;
            TrafficStatisticConfiguration.Server.UpdateTotal += UpdateTotalServer;

            TrafficStatisticConfiguration.Client.Update += UpdateClient;
            TrafficStatisticConfiguration.Client.UpdateTotal += UpdateTotalClient;
        }

        private static void UpdateTotalClient(int requests, long sent, long recieved)
        {
            lock (ClientTraffic)
            {
                ClientTraffic.Total.Requests += requests;
                ClientTraffic.Total.Sent += sent;
                ClientTraffic.Total.Recieved += recieved;
            }
        }

        private static void UpdateClient(string @class, string method, long sent, long recieved)
        {
            ClientTraffic.Add(@class, method, sent, recieved);
        }

        public static void Bind()
        {
        }

        private static void UpdateTotalServer(int requests, long sent, long recieved)
        {
            lock(ServerTraffic)
            {
                ServerTraffic.Total.Requests += requests;
                ServerTraffic.Total.Sent += sent;
                ServerTraffic.Total.Recieved += recieved;
            }
            
        }

        private static void UpdateServer(string @class, string method, long sent, long recieved)
        {
            ServerTraffic.Add(@class, method, sent, recieved);
        }


        private static Thread _Thread;
        private static ManualResetEvent _StopWriting;
        private static object Sync = new object();
        private static string _FileName;
        public static void TurnWritingOn(string fileName, TimeSpan interval)
        {
            if (_Thread != null)
                TurnWritingOff();

            _FileName = fileName;

            lock (Sync)
            {
                ManualResetEvent started = new ManualResetEvent(false);
                _Thread = new Thread(
                    delegate()
                        {
                            started.Set();
                            _StopWriting = new ManualResetEvent(false);
                            while (true)
                            {
                                DateTime start = DateTime.Now;

                                WriteStat(fileName);

                                TimeSpan elapsed = DateTime.Now - start;
                                TimeSpan sleep = interval - elapsed;
                                if (sleep > interval)
                                    sleep = interval;

                                if (sleep < TimeSpan.Zero)
                                    sleep = TimeSpan.Zero;

                                if (_StopWriting.WaitOne(sleep, false))
                                    break;
                            }
                        });

                _Thread.IsBackground = true;
                _Thread.Start();
                started.WaitOne();
            }
        }

        private static void WriteStat(string fileName, TrafficStatistic statistic)
        {
            try
            {
                Encoding enc = null;
                try
                {
                    enc = Encoding.GetEncoding(1252);
                }
                catch
                {
                    enc = Encoding.ASCII;
                }

                using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read))
                using (StreamWriter wr = new StreamWriter(fs, enc))
                {
                    wr.WriteLine(statistic.ToPlainReport());
                }
            }
            catch
            {
            }
            
        }
        private static void WriteStat(string fileName)
        {
            try
            {
                Directory.CreateDirectory(Path.GetDirectoryName(fileName));
            }
            catch
            {
            }

            WriteStat(
                Path.Combine(
                Path.GetDirectoryName(fileName),
                Path.GetFileNameWithoutExtension(fileName)
                + "(server)"
                + Path.GetExtension(fileName)
                ),
                ServerTraffic);

            WriteStat(
                Path.Combine(
                Path.GetDirectoryName(fileName),
                Path.GetFileNameWithoutExtension(fileName)
                + "(client)"
                + Path.GetExtension(fileName)
                ),
                ClientTraffic);

        }

        public static void TurnWritingOn()
        {
            Assembly a = Assembly.GetEntryAssembly();
            if (a == null)
                a = Assembly.GetCallingAssembly();

            if (a == null)
                a = Assembly.GetExecutingAssembly();

            object[] arr1 = a.GetCustomAttributes(typeof (AssemblyProductAttribute), false);
            string product = arr1 != null && arr1.Length > 0 ? ((AssemblyProductAttribute)arr1[0]).Product : null;

            object[] arr2 = a.GetCustomAttributes(typeof (AssemblyCompanyAttribute), false);
            string company = arr2 != null && arr2.Length > 0 ? ((AssemblyCompanyAttribute)arr2[0]).Company : null;

            List<string> parts = new List<string>();
            if (!string.IsNullOrEmpty(company))
                parts.Add(company);

            if (string.IsNullOrEmpty(product))
                parts.Add(product);

            parts.Add(Path.GetFileNameWithoutExtension(a.Location) + ".txt");

            string relative = string.Join(Path.DirectorySeparatorChar.ToString(), parts.ToArray());


            string fileName =
                Path.Combine(
                    Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                    relative
                    );

            TurnWritingOn(fileName, TimeSpan.FromSeconds(10));
        }

        public static void TurnWritingOff()
        {
            if (_Thread != null)
                lock(Sync)
                    if (_Thread != null)
                    {
                        _StopWriting.Set();
                        if (!_Thread.Join(1000))
                            _Thread.Abort();

                        _StopWriting = null;
                        _Thread = null;
                    }

            _FileName = null;
        }

        public static void Flush()
        {
            string fileName = _FileName;
            if (!string.IsNullOrEmpty(fileName))
                WriteStat(fileName);

        }
    }
}